package com.isyscore.os.metadata.service.impl;

import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.isyscore.os.core.model.entity.DataFlowDefinition;
import com.isyscore.os.core.model.entity.DataFlowGroup;
import com.isyscore.os.metadata.dao.DataFlowGroupMapper;
import com.isyscore.os.metadata.model.dto.req.GroupDTO;
import com.isyscore.os.metadata.service.DataFlowDefinitionService;
import com.isyscore.os.metadata.service.DataFlowGroupService;
import org.apache.commons.lang3.StringUtils;
import org.apache.curator.shaded.com.google.common.collect.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author dc
 * @Type DataFlowGroupServiceImpl.java
 * @Desc
 * @date 2022/10/21 11:17
 */
@Service
public class DataFlowGroupServiceImpl extends ServiceImpl<DataFlowGroupMapper, DataFlowGroup> implements DataFlowGroupService {

    @Autowired
    private DataFlowDefinitionService dataFlowDefinitionService;

    /**
     * 新增分组或者新增子分组
     *
     * @param groupDTO
     * @return
     */
    @Override
    public DataFlowGroup addGroup(GroupDTO groupDTO) {
        String name = groupDTO.getName();
        String parentId = groupDTO.getParentId();
        if (StringUtils.isEmpty(parentId)) {
            parentId = null;
        }
        existGroup(name, parentId);
        DataFlowGroup dataFlowGroup = new DataFlowGroup();
        dataFlowGroup.setName(name);
        dataFlowGroup.setParentId(parentId);
        dataFlowGroup.setCreateTime(LocalDateTime.now());
        if (this.save(dataFlowGroup)) {
            return dataFlowGroup;
        }
        return new DataFlowGroup();
    }

    /**
     * 重命名分组
     *
     * @param groupDTO
     * @return
     */
    @Override
    public Boolean updateGroup(GroupDTO groupDTO) {
        String id = groupDTO.getId();
        DataFlowGroup updateId = this.getById(id);
        if ("默认".equals(updateId.getName())) {
            return false;
        }
        DataFlowGroup dbGroup = this.getOne(Wrappers.<DataFlowGroup>lambdaQuery()
                .eq(DataFlowGroup::getId, groupDTO.getId()));
        Assert.notNull(dbGroup, "当前分组不存在:{0}", groupDTO.getName());
        dbGroup.setName(groupDTO.getName());
        return this.updateById(dbGroup);
    }

    /**
     * 删除分组
     * 需求需要递归判断下面是否有子节点，没有任务挂载可以递归删除
     * 1.根据groupid查询是否有任务
     * 1.1 有任务不能删除退出
     * 1.2 无任务
     * 1.2.1 查询此groupid是否有下级
     * 1.2.1.1 无下级 ok删除
     * 1.2.1.2 有下级 递归
     *
     * @param id 分组id
     * @return
     */
    @Override
    public Boolean deleteGroup(String id) {
        DataFlowGroup deleteId = this.getById(id);
        Assert.isFalse("默认".equals(deleteId.getName()), "默认分组不能删除");
        List<DataFlowDefinition> taskList = dataFlowDefinitionService.list(Wrappers.<DataFlowDefinition>lambdaQuery()
                .eq(DataFlowDefinition::getGroupId, id));
        Assert.isFalse(CollectionUtils.isNotEmpty(taskList), "分组下挂有任务不能删除");
        //查询下级
        List<DataFlowGroup> groupList = this.list(Wrappers.<DataFlowGroup>lambdaQuery()
                .eq(DataFlowGroup::getParentId, id));
        if (CollectionUtils.isEmpty(groupList)) {
            return this.removeById(id);
        } else {
            //当前分组有子分组
            List<String> removeIds = new ArrayList<>();
            boolean find = recursionFind(groupList, removeIds);
            if (find) {
                if (CollectionUtils.isNotEmpty(removeIds)) {
                    removeIds.add(id);
                    this.removeByIds(removeIds);
                }
            }
            return find;
        }

    }

    /**
     * 查询分组信息
     *
     * @param parentId
     * @return
     */
    @Override
    public List<DataFlowGroup> getGroup(String parentId) {
        if (StringUtils.isEmpty(parentId)) {
            return this.list(Wrappers.<DataFlowGroup>lambdaQuery()
                    .isNull(DataFlowGroup::getParentId)
                    .orderByAsc(DataFlowGroup::getCreateTime));
        } else {
            return this.list(Wrappers.<DataFlowGroup>lambdaQuery()
                    .eq(DataFlowGroup::getParentId, parentId)
                    .orderByAsc(DataFlowGroup::getCreateTime));
        }
    }

    /**
     * 查询树
     *
     * @return
     */
    @Override
    public List<DataFlowGroup> listTreeGroup() {
        List<DataFlowGroup> list = this.list(Wrappers.<DataFlowGroup>lambdaQuery().orderByDesc(DataFlowGroup::getCreateTime));
        if (CollectionUtils.isNotEmpty(list)) {
            DataFlowGroup defaultGroup = list.get(list.size() - 1);
            list.remove(list.size() - 1);
            list.add(0, defaultGroup);
        }
        return buildTree(list, Lists.newArrayList());
    }


    /**
     * @param list
     * @return
     */
    private List<DataFlowGroup> buildTree(List<DataFlowGroup> list, List<DataFlowGroup> container) {
        if (CollectionUtils.isEmpty(container)) {
            Iterator<DataFlowGroup> iterator = list.iterator();
            while (iterator.hasNext()) {
                DataFlowGroup next = iterator.next();
                if (StringUtils.isEmpty(next.getParentId())) {
                    container.add(next);
                    iterator.remove();
                }
            }
        }
        Map<String, List<DataFlowGroup>> pidListMap = list.stream().collect(Collectors.groupingBy(DataFlowGroup::getParentId));
        doRecursionBuild(container, pidListMap);
        return container;
    }

    private void doRecursionBuild(List<DataFlowGroup> container, Map<String, List<DataFlowGroup>> pidListMap) {
        if (CollectionUtils.isNotEmpty(container)) {
            for (DataFlowGroup dataFlowGroup : container) {
                String id = dataFlowGroup.getId();
                if (pidListMap.containsKey(id)) {
                    List<DataFlowGroup> groupList = pidListMap.get(id);
                    if (CollectionUtils.isNotEmpty(groupList)) {
                        dataFlowGroup.setChildren(groupList);
                    }
                    pidListMap.remove(id);
                    doRecursionBuild(groupList, pidListMap);
                } else {
                    continue;
                }
            }
        }
    }

    /**
     * 递归查询下级分组，并判断是否可以删除
     *
     * @param groupList
     * @return
     */
    private boolean recursionFind(List<DataFlowGroup> groupList, List<String> removeIds) {
        for (DataFlowGroup dataFlowGroup : groupList) {
            List<DataFlowDefinition> taskList = dataFlowDefinitionService.list(Wrappers.<DataFlowDefinition>lambdaQuery()
                    .eq(DataFlowDefinition::getGroupId, dataFlowGroup.getId()));
            Assert.isFalse(CollectionUtils.isNotEmpty(taskList), "分组下挂有任务删除失败");
            List<DataFlowGroup> subGroupList = this.list(Wrappers.<DataFlowGroup>lambdaQuery()
                    .eq(DataFlowGroup::getParentId, dataFlowGroup.getId()));
            if (CollectionUtils.isNotEmpty(subGroupList)) {
                return recursionFind(subGroupList, removeIds);
            } else {
                removeIds.add(dataFlowGroup.getId());
            }
        }
        return true;
    }

    /**
     * 数据分组信息查重
     *
     * @param name
     * @param parentId
     */
    private void existGroup(String name, String parentId) {
        DataFlowGroup dbGroup = this.getOne(Wrappers.<DataFlowGroup>lambdaQuery().eq(DataFlowGroup::getParentId, parentId)
                .eq(DataFlowGroup::getName, name));
        Assert.isNull(dbGroup, "当前分组下存在相同名称：{0}", name);
    }
}

